<template>
  <div class="page page-img-filter-alloyImage">
    <h4 class="text-center">图片批量滤镜处理（alloyImage）</h4>
    <form class="page-body row">
      <div class="col-2">
        <fieldset>
          <legend>效果列表</legend>
          <div class="fieldset-content">
            <div class="form-group effects-list">
              <div v-for="(v,i) in effectsList" :key="i"
                :class="['effect-item', {active: i === effectActiveIndex}]"
                @click="effectItemClick(i)"
              >
                <img :src="v.imgSrc">
                <div class="label">{{v.label}}</div>
              </div>
            </div>
          </div>
        </fieldset>
      </div>
      <div class="col-10">
        <fieldset>
          <legend>操作区域</legend>
          <div class="fieldset-content">
            <div class="form-group preview">
              <img v-if="imageActive.filterImgSrc" :src="imageActive.filterImgSrc" />
              <div v-else class="nodata">图片预览</div>
              <i v-if="imageActive.filterImgSrc" class="fa fa-download" @click="downloadActive" title="下载"></i>
            </div>
            <div class="form-group images-list-wrapper" @drop.prevent="drop" @dragover.prevent>
                <div class="images-list">
                    <div class="images-list-inner">
                        <div v-for="(v,i) in imagesList" :key="i"
                            :class="['image-item', {active: i === imageActiveIndex}]"
                            @click="imageItemClick(i)"
                        >
                            <img :src="v.src">
                            <i class="fa fa-close" @click.stop="imgItemDelete(i)" title="删除"></i>
                        </div>
                    </div>
                </div>
                <div v-show="imagesList.length===0" class="nodata">将待处理图片拖动到此处</div>
            </div>
            <div class="form-group">
              <x-button type="primary" block @click="submitForm" :loading="loadingCount > 0">批量处理&导出</x-button>
            </div>
          </div>
        </fieldset>
      </div>
      <div v-if="loadingCount > 0" class="mask">
        <x-loading></x-loading>
      </div>
    </form>
  </div>
</template>

<script>

const path = global.require('path')

export default {
  name: 'page-img-filter-alloyImage',
  data () {
    return {
      toPath: this.$sharedObject('desktopPath'),
      effectsList: [
        {label: '原图', filter: 'original', imgSrc: this.loadFile('e1.jpg')},
        {label: '美肤效果', filter: 'softenFace', imgSrc: this.loadFile('e1.png')},
        {label: '素描效果', filter: 'sketch', imgSrc: this.loadFile('e2.png')},
        {label: '自然增强', filter: 'softEnhancement', imgSrc: this.loadFile('e3.png')},
        {label: '紫调效果', filter: 'purpleStyle', imgSrc: this.loadFile('e4.png')},
        {label: '柔焦效果', filter: 'soften', imgSrc: this.loadFile('e5.png')},
        {label: '复古效果', filter: 'vintage', imgSrc: this.loadFile('e6.png')},
        {label: '黑白效果', filter: 'gray', imgSrc: this.loadFile('e7.png')},
        {label: '仿lomo', filter: 'lomo', imgSrc: this.loadFile('e8.png')},
        {label: '亮白增强', filter: 'strongEnhancement', imgSrc: this.loadFile('e9.png')},
        {label: '灰白效果', filter: 'strongGray', imgSrc: this.loadFile('e10.png')},
        {label: '灰色效果', filter: 'lightGray', imgSrc: this.loadFile('e11.png')},
        {label: '暖秋效果', filter: 'warmAutumn', imgSrc: this.loadFile('e12.png')},
        {label: '木雕效果', filter: 'carveStyle', imgSrc: this.loadFile('e13.png')},
        {label: '粗糙效果', filter: 'rough', imgSrc: this.loadFile('e14.png')},
      ],
      effectActiveIndex: 0,
      imagesList: [],
      imageActiveIndex: -1,
      loadingCount: 0
    }
  },
  computed: {
      effectActive () {
        return this.effectsList[this.effectActiveIndex] || {}
      },
      imageActive () {
        return this.imagesList[this.imageActiveIndex] || {}
      }
  },
  mounted () {
  },
  methods: {
    // 拖拽添加图片
    drop (e) {
      const fileList = e.dataTransfer.files
      if (!fileList) return
      // 文件类型不存在即认为是文件夹或特殊文件
      // 取文件后缀名，必须是图片文件
      let taskList = []
      let indexList = []
      for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        if (!file.type) {
          return this.$toast('不支持文件夹及特殊格式文件！')
        }
        if (!/.(gif|jpg|jpeg|png|gif|jpg|png)$/i.test(file.name)) {
          return this.$toast('请选择图片文件！')
        }
        taskList.push(this.$jstools.File2dataUrl(file))
        indexList.push(i)
      }
      Promise.all(taskList).then((urls) => {
        urls.forEach((v, i) => {
          let file = fileList[indexList[i]]
          this.imagesList.push({
            name: file.name, src: v, path: file.path, mimeType: file.type,
            originWidth: 0, originHeight: 0, imgObj: null,
            canvas: null, filterImgSrc: '', filter: 'original',
          })
        })
        this.loadImage()
      })
    },
    // 加载原始图片
    loadImage () {
      this.imagesList.forEach((v, i) => {
        if (v.imgObj) return
        this.$jstools.loadImage(v.src).then((imgObj) => {
          this.imagesList[i].imgObj = imgObj
          this.imagesList[i].originWidth = imgObj.width
          this.imagesList[i].originHeight = imgObj.height
        })
      })
    },
    // 删除图片
    imgItemDelete (index) {
      this.imagesList.splice(index, 1)
      if (this.imageActiveIndex === index) {
        this.imageActiveIndex = -1
      } else if (this.imageActiveIndex > index) {
        this.imageActiveIndex -= 1
      }
    },
    // 效果Item被点击
    effectItemClick (index) {
      if (this.effectActiveIndex === index) return
      this.effectActiveIndex = index
      this.imagesList = this.imagesList.map(v => {
        v.filter = 'original'
        v.canvas = null
        v.filterImgSrc = ''
        return v
      })
      if (this.imageActiveIndex > -1) {
        this.loadingCount++
        setTimeout(() => {
          this.filterItem(this.imageActiveIndex).finally(() => {
            this.loadingCount--
          })
        }, 0)
      }
    },
    // 图片Item被点击
    imageItemClick (index) {
      if (this.imageActiveIndex === index) return
      this.imageActiveIndex = index
      this.loadingCount++
      setTimeout(() => {
        this.filterItem(index).finally(() => {
          this.loadingCount--
        })
      }, 0)
    },
    // 下载当前图片
    downloadActive () {
      if (!this.imageActive.canvas) return
      this.imageActive.canvas.toBlob((blob) => {
        if (blob) {
          let fp = path.join(this.toPath, this.imageActive.name)
          this.saveBlob(blob, this.imageActive.name).then(() => {
            this.$toast(`下载完成，图片保存在 ${fp}`)
          })
        }
      })
    },
    // 单张处理
    filterItem (index) {
      return new Promise((resolve, reject) => {
        let imageItem = this.imagesList[index] || {}
        let {originWidth, originHeight} = imageItem
        if (!originWidth || !originHeight) {
          this.$toast('图片信息错误')
          reject('图片信息错误')
        } else if (imageItem.filterImgSrc && (imageItem.filter === this.effectActive.filter)) {
          resolve(imageItem)
        } else {
          let newImgObj = window.$AI(imageItem.imgObj)
          newImgObj = newImgObj.ps(this.effectActive.label.replace('效果', ''))
          imageItem.canvas = newImgObj.canvas
          imageItem.filterImgSrc = newImgObj.save()
          imageItem.filter = this.effectActive.filter
          this.imagesList[index] = imageItem
          resolve(imageItem)
        }
      })
    },
    // 将Blob数据写到本地磁盘
    saveBlob (blob, filename) {
      if (!blob || !filename) return Promise.reject()
      return blob.arrayBuffer().then((res) => {
        let fp = path.join(this.toPath, filename)
        this.$sharedObject('jstoolsNode').writeFile(fp, Buffer.from(res))
      }).catch((err) => {
        this.$toast('发生错误：' + err)
      })
    },
    // 批量处理&导出
    submitForm () {
      let taskList = []
      this.imagesList.forEach((v, i) => {
        taskList.push(
          this.filterItem(i).then((imageItem) => {
            if (!imageItem.canvas) return
            imageItem.canvas.toBlob((blob) => {
              if (blob) {
                this.saveBlob(blob, imageItem.name)
              }
            })
          })
        )
      })
      this.loadingCount++
      Promise.all(taskList).finally(() => {
        this.$toast('操作已完成')
        this.loadingCount--
      })
    },
    loadFile (filename) {
      return require(`@/assets/images/alloyImage/${filename}`)
    },
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
@gapSize: 10px;

.page-img-filter-alloyImage {
  display: flex;
  flex-direction: column;
  .page-body {
    height: 0;
    flex-grow: 1;
    position: relative;
    fieldset {
      height: 100%;
      .fieldset-content {
        height: calc(100% - 2em);
        display: flex;
        flex-direction: column;
      }
      .effects-list {
        height: 0;
        flex-grow: 1;
        border-radius: 6px;
        background-color: rgba(0,0,0,.1);
        overflow-y: auto;
        .effect-item {
          margin: @gapSize;
          background-color: rgba(0,0,0,.1);
          border-radius: 6px;
          border-width: 4px;
          border-style: solid;
          border-color: transparent;
          overflow: hidden;
          position: relative;
          img {
            display: block;
            width: 100%;
            height: 6vw;
            object-fit: cover;
          }
          .label {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            padding: .25em;
            font-size: 1vw;
            color: #fff;
            text-align: center;
            letter-spacing: .1em;
            background-color: rgba(0,0,0,.5);
          }
          &.active {
            border-color: #fff;
          }
          .fa-close {
            position: absolute;
            top: 0;
            right: 0;
            z-index: 2;
            padding: .15em 0.5em;
            font-size: 1vw;
            color: #fff;
            border-radius: 0 0 0 .3em e('/') 0 0 0 .3em;
            background-color: @colorPrimary;
            cursor: pointer;
          }
        }
      }
      .preview {
        height: 0;
        flex-grow: 1;
        border-radius: 6px;
        background-color: rgba(0,0,0,.1);
        overflow: hidden;
        position: relative;
        img {
          .absolute-fullscreen;
          width: 100%;
          height: 100%;
          object-fit: contain;
        }
        .fa-download {
          position: absolute;
          top: 0;
          right: 0;
          z-index: 2;
          padding: .5em 1em;
          font-size: 1vw;
          color: #fff;
          border-radius: 0 0 0 .3em e('/') 0 0 0 .3em;
          background-color: @colorPrimary;
          cursor: pointer;
        }
      }
      .images-list-wrapper {
        height: 150px;
        border-radius: 6px;
        background-color: rgba(0,0,0,.1);
        position: relative;
        .images-list {
          position: absolute;
          left: @gapSize;
          right: @gapSize;
          top: @gapSize;
          bottom: @gapSize;
          overflow: auto hidden;
        }
        .images-list-inner {
          display: flex;
          flex-wrap: nowrap;
        }
        .image-item {
          border-width: 2px;
          border-style: solid;
          border-color: transparent;
          border-radius: .3em;
          background-color: rgba(255,255,255,.3);
          overflow: hidden;
          position: relative;
          img {
            display: inline-block;
            height: 130px;
            width: auto;
          }
          .fa-close {
            position: absolute;
            top: 0;
            right: 0;
            z-index: 2;
            padding: .15em 0.5em;
            font-size: 1vw;
            color: #fff;
            border-radius: 0 0 0 .3em e('/') 0 0 0 .3em;
            background-color: @colorPrimary;
            cursor: pointer;
          }
          &.active {
            border-color: @colorWarning;
          }
          &:not(:last-child) {
            margin-right: @gapSize;
          }
        }
      }
    }
    .mask {
      position: absolute;
      left: 15px;
      right: 15px;
      top: 0;
      bottom: 0;
      border-radius: 8px;
      background-color: rgba(255,255,255,.5);
      .flex-center;
    }
  }
}
</style>
